package com.iflytek.read;

import android.annotation.SuppressLint;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.net.http.SslError;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
import android.provider.MediaStore;
import android.provider.OpenableColumns;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.JavascriptInterface;
import android.webkit.SslErrorHandler;
import android.webkit.WebResourceError;
import android.webkit.WebResourceRequest;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;

import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import com.hjq.permissions.OnPermissionCallback;
import com.hjq.permissions.Permission;
import com.hjq.permissions.XXPermissions;
import com.hjq.toast.Toaster;
import com.iflytek.read.bean.AudioRecordInfo;
import com.iflytek.read.bean.BaseResponse;
import com.iflytek.read.bean.CustomFile;
import com.iflytek.read.bean.FileSliceInfo;
import com.iflytek.read.bean.FloatWindowBean;
import com.iflytek.read.bean.SaveFileInfoBean;
import com.iflytek.read.bean.UploadBean;
import com.iflytek.read.bean.UserInfo;
import com.iflytek.read.util.DownloaderUtil;
import com.iflytek.read.util.LogUtil;
import com.iflytek.read.util.MultipartBuilderHelper;
import com.iflytek.read.util.RotationUtil;
import com.iflytek.read.util.RsaUtils;
import com.iflytek.read.util.ThreadPoolUtils;
import com.iflytek.read.window.EasyWindow;
import com.iflytek.read.window.draggable.SpringBackDraggable;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Type;
import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;

/**
 * @author wangshuai
 */
public final class ReadWebViewActivity extends AppCompatActivity implements DownloaderUtil.DownloadListener {

    private final String TAG = this.getClass().getName();

    private Messenger activityMessenger;

    /**
     * 添加成员变量
     */
    private MultipartBuilderHelper multipartHelper;

    private final ExecutorService singleThreadPool = ThreadPoolUtils.newSingleThreadExecutor("my-single-pool");

    public interface OnCompletionCallback {

        /**
         * 获取下一个要播放的音频链接
         * @param playerId  音乐播放器id
         * @param bean      参数
         * @param callback  回调
         */
        void getNextAudioUrl(int playerId, FloatWindowBean bean, NextAudioCallback callback);
    }

    private ImageView btnImg;

    public interface NextAudioCallback {

        /**
         * 获取到下一个要播放的音频信息
         * @param nextBean  音频信息
         */
        void onNextAudioReady(FloatWindowBean nextBean);

        /**
         * 获取失败
         * @param e 失败信息
         */
        void onError(Exception e);
    }

    private final OnCompletionCallback completionCallback = new OnCompletionCallback() {
        @Override
        public void getNextAudioUrl(int playerId, FloatWindowBean bean, NextAudioCallback callback) {
            if (playerId == 1) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        btnImg.setEnabled(false);
                        RotationUtil.startRotation(btnImg);
                    }
                });

                getNextFileSlice(bean, new NextAudioCallback() {
                    @Override
                    public void onNextAudioReady(FloatWindowBean nextBean) {
                        Log.i(TAG, "nextBean ready: " + nextBean);
                        if (Constant.TYPE_CURRENT_PLAY != nextBean.getType()) {
                            //nextBean.setCurrentIndex(nextBean.getIndex());
                            callback.onNextAudioReady(nextBean);
                            runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    currentBean = nextBean;
                                    btnImg.setEnabled(true);
                                    RotationUtil.stopRotation(btnImg);
                                    btnImg.setBackgroundResource(R.mipmap.read_float_window_pause);
                                    isPlayIng = musicPlayerService.isPlaying(1);
                                }
                            });
                        }
                    }

                    @Override
                    public void onError(Exception e) {
                        LogUtil.e(TAG, "onError  ==  ");

                        saveAsFileInfo(false);
                        if (null != currentBean && !TextUtils.isEmpty(currentBean.getNovelId())) {
                            try {
                                JSONObject obj = new JSONObject();
                                obj.put(Constant.KEY_NAME_NOVEL_ID, currentBean.getNovelId());
                                obj.put(Constant.KEY_NAME_PLAY_TYPE, "2");
                                androidCallJavaScript(13, obj.toString());
                            } catch (Exception ex) {
                                LogUtil.e(TAG, "ex  ==  " + e.getMessage());
                            }
                        }

                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                currentBean = null;
                                stopMusic(1);
                                stopMusic(2);
                                btnImg.setEnabled(true);
                                RotationUtil.stopRotation(btnImg);
                                btnImg.setBackgroundResource(R.mipmap.read_float_window_play);
                                isPlayIng = musicPlayerService.isPlaying(1);
                            }
                        });

                        callback.onError(e);
                    }
                });
            } else {
                callback.onNextAudioReady(null);
            }
        }
    };

    private UserInfo userInfo;
    private FloatWindowBean currentBean;
    private int currentType = -1;

    private static final int REQUEST_PERMISSION_CODE = 1001;
    private static final int REQUEST_MANAGE_STORAGE = 2001;
    private static final int REQUEST_FILE_PICKER = 3001;

    private WebView webView;

    private final List<CustomFile> fileList = new CopyOnWriteArrayList<>();
    /**
     * 这个变量用来在 onActivityResult 回调中判断是搜索文件还是查看目录
     */
    private int resultType = -1;
    /**
     * 如果 resultType = 1，就会用到 resultFile
     */
    private File resultFile;

    /**
     * 播放 service
     */
    private MusicPlayerService musicPlayerService;
    /**
     * 服务是否绑定
     */
    private boolean isServiceBound = false;

    /**
     * 切换悬浮窗上面的播放/暂停按钮
     */
    private boolean isPlayIng = false;

    private final ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            MusicPlayerBinder binder = (MusicPlayerBinder) service;
            musicPlayerService = binder.getService();
            musicPlayerService.setOnCompletionCallback(completionCallback); // 设置回调
            binder.setActivityMessenger(activityMessenger);
            isServiceBound = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            isServiceBound = false;
        }
    };

    private void bindToService() {
        // Bind to the service
        Intent serviceIntent = new Intent(this, MusicPlayerService.class);
        startService(serviceIntent);
        bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.read_webview_activity);

        Intent intent = getIntent();
        if (null != intent) {
            String token;
            String userId;
            String userName;
            token = intent.getStringExtra(Constant.KEY_TOKEN);
            userId = intent.getStringExtra(Constant.KEY_USER_ID);
            userName = intent.getStringExtra(Constant.KEY_USER_NAME);

            /*{
                "accessToken": {
                "expirationTime": 1745841807504,
                        "token": "d320d362ed8a4d40a3b384e5aa81a43d"
            },
                "id": 2332937,
                    "isDisabled": 0,
                    "loginName": "T1199532",
                    "mobile": "15010064227",
                    "name": "冯二运",
                    "namePinyin": "fengeryun",
                    "orgId": 1,
                    "refreshToken": {
                "expirationTime": 1747829008000,
                        "token": "2a46942e6b1a4213a0254918787bf6c6"
            },
                "userOrigin": 0
            }*/

            /*token = "d320d362ed8a4d40a3b384e5aa81a43d";
            user_id = "2332937";
            user_name = "冯二运";*/

            try {
                if (!TextUtils.isEmpty(token) && !TextUtils.isEmpty(userId)) {
                    userInfo = new UserInfo();
                    userInfo.setToken(token);
                    String deviceId = Settings.Secure.getString(this.getContentResolver(), Settings.Secure.ANDROID_ID)+this.getPackageName();
                    userInfo.setUserId(RsaUtils.encryptByPublicKeyStr(Base64.getEncoder().encodeToString(deviceId.getBytes()), userId));
                    userInfo.setUserName(userName);
                }

                Log.i(TAG, "token  ==  " + userInfo.getToken());
                Log.i(TAG, "user_id  ==  " + userInfo.getUserId());
                Log.i(TAG, "user_name  ==  " + userInfo.getUserName());
            } catch (Exception e) {
                LogUtil.e(TAG, "用户ID加密失败  ==  " + e.getMessage());
            }
        }

        Toaster.init(getApplication());

        // 初始化 Handler 和 Messenger
        Handler handler = new Handler(Looper.getMainLooper()) {
            @Override
            public void handleMessage(Message msg) {

                // 在这里处理 musicService 发出的消息
                if (msg.what == Constant.SERVICE_SEND_MSG_TYPE) {
                    String novelId = (String) msg.obj;
                    Log.i(TAG, "Received novelId from service: " + novelId);
                    try {
                        JSONObject obj = new JSONObject();
                        obj.put(Constant.KEY_NAME_NOVEL_ID, currentBean.getNovelId());
                        obj.put(Constant.KEY_NAME_PLAY_TYPE, "1");
                        androidCallJavaScript(13, obj.toString());
                    } catch (Exception e) {
                        LogUtil.e(TAG, "handleMessage--e  ==  " + e.getMessage());
                    }
                }
            }
        };

        activityMessenger = new Messenger(handler);

        bindToService();
        initWebView();
        initMethod();
    }

    private void initMethod() {

        //初始化工具类
        multipartHelper = new MultipartBuilderHelper(userInfo);
    }

    @SuppressLint({"JavascriptInterface", "SetJavaScriptEnabled"})
    private void initWebView() {
        webView = findViewById(R.id.webView);
        WebSettings settings = webView.getSettings();
        webView.setWebViewClient(new CustomClient());

        // 设置 webView 支持javascript
        settings.setJavaScriptEnabled(true);
        // 支持自动加载图片
        settings.setLoadsImagesAutomatically(true);
        // 设置 webView 推荐使用的窗口，使html界面自适应屏幕
        settings.setUseWideViewPort(true);
        settings.setLoadWithOverviewMode(true);
        settings.setDomStorageEnabled(true);
        settings.setCacheMode(WebSettings.LOAD_DEFAULT);
        settings.setAllowContentAccess(true);
        settings.setAllowFileAccess(true);
        webView.setOnKeyListener((v, keyCode, event) -> {
            if (event.getAction() == KeyEvent.ACTION_DOWN) {
                if (keyCode == KeyEvent.KEYCODE_BACK && webView.canGoBack()) {
                    //表示按返回键时的操作
                    webView.goBack();
                    return true;
                }
            }
            return false;
        });

        webView.addJavascriptInterface(this, "js2android");

        Log.i(TAG, "BuildConfig.DEBUG  ==  " + BuildConfig.DEBUG);
        if (BuildConfig.DEBUG) {
            webView.loadUrl(Constant.H5_URL_TEST);
        } else {
            webView.loadUrl(Constant.H5_URL);
        }
    }

    /********************js桥开始*************************/
    /**
     * 提供给 H5 调用的  获取用户信息方法
     */
    @JavascriptInterface
    public void getUserInfo() {

        try {
            if (null != userInfo) {
                Gson gson = new Gson();
                String json = gson.toJson(userInfo);
                androidCallJavaScript(10, json);
            }
        } catch (Exception e) {
            LogUtil.e(TAG, "getUserInfo + e  ==  " + e.getMessage());
        }
    }

    /**
     * 提供给 H5 调用的  搜索文件方法
     */
    @JavascriptInterface
    public void searchDefaultFiles() {

        try {
            checkAndRequestPermissions(null, 2);
        } catch (Exception e) {
            LogUtil.e(TAG, "searchDefaultFiles + e  ==  " + e.getMessage());
        }
    }

    /**
     * 提供给 H5 调用的 点击按钮后 搜索文件方法
     * @param query 搜索参数
     */
    @JavascriptInterface
    public void performSearch(String query) {

        try {
            fileList.clear();
            singleThreadPool.execute(() -> {
                if (query.isEmpty()) {
                    loadDefaultFiles();
                } else if (isExtensionSearch(query)) {
                    handleExtensionSearch(query);
                } else {
                    handleExactSearch(query);
                }
                sortAndUpdateUi(6);
            });
        } catch (Exception e) {
            LogUtil.e(TAG, "performSearch + e  ==  " + e.getMessage());
        }
    }

    /**
     * 提供给 H5 调用的 批量上传文件方法
     * @param jsonStr   上传文件的json数据
     */
    @JavascriptInterface
    public void jsUploadFiles(String jsonStr) {
        try {
            Log.i(TAG, "jsonStr  ==  " + jsonStr);
            singleThreadPool.execute(new Runnable() {
                @Override
                public void run() {
                    // 将 json 字符串 使用 Gson 解析 JSON 字符串
                    Gson gson = new Gson();
                    UploadBean bean = gson.fromJson(jsonStr, UploadBean.class);
                    if (null != bean.getFilePaths() && bean.getFilePaths().size() != 0) {
                        List<File> files = new ArrayList<>();
                        File file;
                        for (String filePath : bean.getFilePaths()) {
                            file = new File(filePath);
                            if (file.exists() && file.isFile()) {
                                files.add(file);
                            }
                        }
                        uploadFiles(files, bean.getAnchorName(), bean.getSpeed(), bean.getVolume());
                    }
                }
            });
        } catch (Exception e) {
            LogUtil.e(TAG, "jsUploadFiles + e  ==  " + e.getMessage());
        }
    }

    /**
     * 提供给 H5 调用的  获取文件目录方法
     * @param filePath  查询的文件目录参数
     */
    @JavascriptInterface
    public void getDirectoryAndFile(String filePath) {

        Log.i(TAG, "filePath  ==  " + filePath);
        try {
            int type = 1;
            File file;
            if (!TextUtils.isEmpty(filePath)) {
                file = new File(filePath);
            } else {
                file = Environment.getExternalStorageDirectory();
            }
            checkAndRequestPermissions(file, type);
        } catch (Exception e) {
            LogUtil.e(TAG, "getDirectoryAndFile + e  ==  " + e.getMessage());
        }
    }

    /**
     * 提供给 H5 调用的  展示悬浮框方法
     * @param jsonStr   展示悬浮框参数
     */
    @JavascriptInterface
    public void jsShowOrCancelFloatWindow(String jsonStr) {

        try {
            singleThreadPool.execute(() -> {
                if (!TextUtils.isEmpty(jsonStr)) {
                    windowShow(jsonStr);
                }
            });
        } catch (Exception e) {
            LogUtil.e(TAG, "jsShowOrCancelFloatWindow + e  ==  " + e.getMessage());
        }
    }

    /**
     * H5 从 首页跳转到听单列表页 调用的 js 桥
     * @return  返回当前播放的文件id
     */
    @JavascriptInterface
    public String returnFileId() {
        try {
            if (null != currentBean) {
                isPlayIng = musicPlayerService.isPlaying(Constant.PLAYER_ID_1);
                JSONObject obj = new JSONObject();
                obj.put(Constant.KEY_NAME_NOVEL_ID, currentBean.getNovelId());
                if (isPlayIng) {
                    obj.put(Constant.KEY_NAME_PLAY_TYPE, "1");
                } else {
                    obj.put(Constant.KEY_NAME_PLAY_TYPE, "2");
                }

                Log.i(TAG, "returnFileId()  ==  " + obj);
                return obj.toString();
            }
        } catch (Exception e) {
            LogUtil.e(TAG, "returnFileId  异常  ==  " + e.getMessage());
        }

        return "";
    }

    private void windowShow(String jsonStr) {
        // 将 json 字符串 使用 Gson 解析 JSON 字符串
        Log.i(TAG, "windowShow  jsonStr  ==  " + jsonStr);
        Gson gson = new Gson();
        FloatWindowBean bean = gson.fromJson(jsonStr, FloatWindowBean.class);

        currentType = bean.getType();
        if (null != musicPlayerService) {
            musicPlayerService.setCurrentType(currentType);
        }

        if (Constant.TYPE_SHOW_FLOAT_WINDOW_1 == bean.getType()) {
            runOnUiThread(() -> {
                showEasyWindow();
                if (!TextUtils.isEmpty(bean.getUrl1())) {
                    currentBean = bean;
                    String fileName = bean.getChapterId() + "_" + System.currentTimeMillis() + ".wav";
                    // 开始下载
                    DownloaderUtil.downloadWavFile(this, bean, bean.getUrl1(), fileName, this);
                }
            });
        } else if (Constant.TYPE_SHOW_FLOAT_WINDOW_3 == bean.getType()) {
            runOnUiThread(() -> {
                showEasyWindow();
                btnImg.setEnabled(false);
                RotationUtil.startRotation(btnImg);
                btnImg.setBackgroundResource(R.mipmap.read_float_window_pause);
            });

            if (null != currentBean) {
                Log.i(TAG, "currentBean  ==  " + currentBean);
                if (currentBean.getNovelId().equals(bean.getNovelId())) {
                    musicPlayerService.startPlayer();

                    try {
                        JSONObject obj = new JSONObject();
                        obj.put(Constant.KEY_NAME_NOVEL_ID, currentBean.getNovelId());
                        obj.put(Constant.KEY_NAME_PLAY_TYPE, "1");
                        androidCallJavaScript(13, obj.toString());
                    } catch (Exception e) {
                        LogUtil.e(TAG, "type = 3 异常  ==  " + e.getMessage());
                    }

                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            btnImg.setEnabled(true);
                            RotationUtil.stopRotation(btnImg);
                        }
                    });
                } else {
                    if (null != musicPlayerService) {
                        musicPlayerService.stopAudio(1);
                    }
                    getCurrentFileSlice(bean);
                    saveAsFileInfo(false);
                }
            } else {
                Log.i(TAG, "currentBean  ==  " + null);
                getCurrentFileSlice(bean);
            }
        } else if (Constant.TYPE_SHOW_FLOAT_WINDOW_2 == bean.getType()) {
            runOnUiThread(() -> {
                cancelEasyWindow();
                stopMusic(1);
                stopMusic(2);
                String json = gson.toJson(false);
                androidCallJavaScript(9, json);
                isPlayIng = musicPlayerService.isPlaying(1);
            });
        } else if (Constant.TYPE_SHOW_FLOAT_WINDOW_4 == bean.getType()) {
            /**
             * 停止播放，保存播放记录 和 配置  调用 saveFileInfo();
             */
            pauseMusic(1);
            pauseMusic(2);
            saveAsFileInfo(true);

            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    if (null != btnImg) {
                        btnImg.setEnabled(true);
                        RotationUtil.stopRotation(btnImg);
                        btnImg.setBackgroundResource(R.mipmap.read_float_window_play);
                    }
                    isPlayIng = musicPlayerService.isPlaying(1);
                }
            });
        }
    }

    /**
     * 提供给 H5 调用的获取 raw 文件夹 MP3 列表方法
     */
    @JavascriptInterface
    public void getRawMp3List() {
        if (isServiceBound) {
            Map<String, Integer> mp3Files = musicPlayerService.getRawMp3Files();

            // 转换为 JSON 格式返回给 H5
            JSONArray jsonArray = new JSONArray();
            for (Map.Entry<String, Integer> entry : mp3Files.entrySet()) {
                JSONObject jsonObject = new JSONObject();
                try {
                    jsonObject.put("name", entry.getKey());
                    jsonObject.put("resId", entry.getValue());
                    jsonArray.put(jsonObject);
                } catch (JSONException e) {
                    LogUtil.e(TAG, "Error creating JSON: " + e.getMessage());
                }
            }

            androidCallJavaScript(14, jsonArray.toString());
        }
    }

    /**
     * 提供给 H5 调用的播放 raw 文件夹 MP3 方法
     * @param resId MP3 文件资源ID
     */
    @JavascriptInterface
    public void playRawMp3(int resId) {
        if (isServiceBound) {
            musicPlayerService.playRawMp3(resId);
        }
    }

    /**
     * 提供给 H5 调用的获取 assets MP3 列表方法
     */
    @JavascriptInterface
    public void getAssetsMp3List() {
        if (isServiceBound) {
            List<String> mp3Files = musicPlayerService.getAssetsMp3Files();

            // 转换为 JSON 数组
            JSONArray jsonArray = new JSONArray();
            for (String fileName : mp3Files) {
                jsonArray.put(fileName);
            }

            androidCallJavaScript(15, jsonArray.toString());
        }
    }

    /**
     * 提供给 H5 调用的播放 assets MP3 方法
     * @param fileName MP3 文件名
     */
    @JavascriptInterface
    public void playAssetsMp3(String fileName, int playType) {
        Log.i(TAG, "playAssetsMp3  ==  " + fileName + "\t\t" + playType);
        if (isServiceBound) {

            if (Constant.TYPE_PLAY_BG_MUSIC_1 == playType) {
                if (!fileName.isEmpty()) {
                    if (null != currentBean && !fileName.equals(currentBean.getUrl2())) {
                        currentBean.setUrl2(fileName);
                        musicPlayerService.stopAudio(Constant.PLAYER_ID_2);
                        musicPlayerService.playAssetsMp3(fileName);
                    } else {
                        if (null != currentBean) {
                            currentBean.setUrl2(fileName);
                        }
                        musicPlayerService.playAssetsMp3(fileName);
                    }
                } else {
                    musicPlayerService.stopAudio(Constant.PLAYER_ID_2);
                }
            } else {
                pauseMusic(2);
            }
        }
    }

    /**
     * 左上角返回按钮
     */
    @JavascriptInterface
    public void leftTopBackButtonClick() {
        finish();
    }

    /**
     * 安卓 将数据发送给 H5 统一要调用的方法
     * @param type  类型
     * @param json  返回给H5的json格式数据
     */
    private void androidCallJavaScript(int type, String json) {
        runOnUiThread(() -> {
            // 在这里调用 js 提供的方法
            Log.i(TAG, "type  ==  " + type);
            Log.i(TAG, "json  ==  " + json);
            switch (type) {
                case 5:
                    webView.evaluateJavascript("javascript:getAllFiles('" + json + "')", null);
                    break;
                case 6:
                    webView.evaluateJavascript("javascript:getSearchFiles('" + json + "')", null);
                    break;
                case 7:
                    webView.evaluateJavascript("javascript:getFilesList('" + json + "')", null);
                    break;
                case 8://H5调用安卓js桥，安卓调用文件上传接口，接口返回值发送给H5
                    webView.evaluateJavascript("javascript:addBook('" + json + "')", null);
                    break;
                case 9:
                    webView.evaluateJavascript("javascript:getFloating('" + json + "')", null);
                    break;
                case 10:
                    webView.evaluateJavascript("javascript:getUserData('" + json + "')", null);
                    break;
                case 11:
                    webView.evaluateJavascript("javascript:jumpDetail('" + json + "')", null);
                    break;
                case 13://传给H5  文件id  H5 收到后， 听单列表如果有这个文件id，正在播放就暂停，暂停就开始播放
                    webView.evaluateJavascript("javascript:getPlayType('" + json + "')", null);
                    break;
                default:
            }
        });
    }

    /********************js桥结束*************************/

    /**
     * 权限申请
     */
    private void noUsage() {
        XXPermissions.with(ReadWebViewActivity.this).permission(Permission.SYSTEM_ALERT_WINDOW).request(new OnPermissionCallback() {

            @Override
            public void onGranted(@NonNull List<String> permissions, boolean allGranted) {
                // 这里最好要做一下延迟显示，因为在某些手机（华为鸿蒙 3.0）上面立即显示会导致显示效果有一些瑕疵
                runOnUiThread(() -> {

                });
            }

            @Override
            public void onDenied(@NonNull List<String> permissions, boolean doNotAskAgain) {
                EasyWindow.with(ReadWebViewActivity.this)
                        .setDuration(5000)
                        .setContentView(R.layout.read_window_hint)
                        .setImageDrawable(android.R.id.icon, R.mipmap.read_dialog_tip_error)
                        .setText(android.R.id.message, "请先授予悬浮窗权限")
                        .show();
            }
        });
    }

    /**
     * 目前此方法没有使用的
     * 全局弹窗要验证 悬浮框权限
     * @param jsonStr   参数
     */
    private void checkAlertWindow(String jsonStr) {

        XXPermissions.with(ReadWebViewActivity.this)
                .permission(Permission.SYSTEM_ALERT_WINDOW)
                .request(new OnPermissionCallback() {
                    @Override
                    public void onGranted(@NonNull List<String> permissions, boolean allGranted) {
                        // 这里最好要做一下延迟显示，因为在某些手机（华为鸿蒙 3.0）上面立即显示会导致显示效果有一些瑕疵
                        runOnUiThread(() -> {

                        });
                    }

                    @Override
                    public void onDenied(@NonNull List<String> permissions, boolean doNotAskAgain) {
                        if (doNotAskAgain) {
                            // 如果是被永久拒绝，直接跳转到应用悬浮窗权限设置页
                            XXPermissions.startPermissionActivity(ReadWebViewActivity.this, Permission.SYSTEM_ALERT_WINDOW);
                        } else {
                            Toast.makeText(ReadWebViewActivity.this, "请授予悬浮窗权限", Toast.LENGTH_LONG).show();
                        }
                    }
                });
    }

    /**
     * 显示 可拖拽的悬浮框
     */
    private void showEasyWindow() {
        // 先检查悬浮窗权限
        if (!XXPermissions.isGranted(ReadWebViewActivity.this, Permission.SYSTEM_ALERT_WINDOW)) {
            XXPermissions.with(ReadWebViewActivity.this)
                    .permission(Permission.SYSTEM_ALERT_WINDOW)
                    .request(new OnPermissionCallback() {
                        @Override
                        public void onGranted(@NonNull List<String> permissions, boolean allGranted) {
                            // 获得权限后显示悬浮窗
                            showEasyWindowImpl();
                        }

                        @Override
                        public void onDenied(@NonNull List<String> permissions, boolean doNotAskAgain) {
                            Toast.makeText(ReadWebViewActivity.this, "需要悬浮窗权限来显示播放控制器", Toast.LENGTH_SHORT).show();
                        }
                    });
            return;
        }

        // 已有权限，直接显示
        showEasyWindowImpl();
    }

    // 实际显示悬浮窗的逻辑
    private void showEasyWindowImpl() {
        if (null != musicPlayerService) {
            Log.i(TAG, "musicPlayerService.isPlaying  ==  " + musicPlayerService.isPlaying(1));
            if (musicPlayerService.isPlaying(1)) {
                if (null != musicPlayerService.getFloatBean()) {
                    currentBean = musicPlayerService.getFloatBean();
                }
            }
            isPlayIng = musicPlayerService.isPlaying(1);
        }

        Log.i(TAG, "EasyWindow.existAnyWindowShowing()  ==  " + EasyWindow.existAnyWindowShowing());
        if (!EasyWindow.existAnyWindowShowing()) {

            View floatView = getFloatView();

            SpringBackDraggable springBackDraggable = new SpringBackDraggable(SpringBackDraggable.ORIENTATION_HORIZONTAL);
            EasyWindow.with(ReadWebViewActivity.this)
                    .setGravity(Gravity.BOTTOM | Gravity.RIGHT)
                    .setOffSetX(50)
                    .setOffSetY(50)
                    .setContentView(floatView)
                    // 设置成可拖拽的
                    .setDraggable(springBackDraggable)
                    .setOnClickListener(R.id.img_close, new EasyWindow.OnClickListener<RelativeLayout>() {

                        @Override
                        public void onClick(EasyWindow<?> easyWindow, RelativeLayout view) {
                            saveAsFileInfo(false);
                            easyWindow.cancel();
                            stopMusic(1);
                            stopMusic(2);

                            try {
                                JSONObject obj = new JSONObject();
                                obj.put(Constant.KEY_NAME_NOVEL_ID, currentBean.getNovelId());
                                obj.put(Constant.KEY_NAME_PLAY_TYPE, "2");
                                androidCallJavaScript(13, obj.toString());
                            } catch (Exception e) {
                                LogUtil.e(TAG, "img_close 异常  ==  " + e.getMessage());
                            }
                        }
                    })
                    .show();

            if (isPlayIng) {
                btnImg.setBackgroundResource(R.mipmap.read_float_window_pause);
            } else {
                btnImg.setBackgroundResource(R.mipmap.read_float_window_play);
            }
        }
    }

    private View getFloatView() {

        View floatView = View.inflate(getApplicationContext(), R.layout.read_float_window_layout, null);

        // 设置宽高
        int widthInPixels = (int) TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_DIP,
                142,
                getResources().getDisplayMetrics()
        );
        int heightInPixels = (int) TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_DIP,
                50,
                getResources().getDisplayMetrics()
        );

        ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(widthInPixels, heightInPixels);
        floatView.setLayoutParams(layoutParams);

        btnImg = floatView.findViewById(R.id.img_action);

        btnImg.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                currentType = -1;
                Log.i(TAG, "111-isPlayIng  ==  " + isPlayIng);
                if (null != currentBean) {
                    Log.i(TAG, "currentBean  ==  " + currentBean);
                    if (null != musicPlayerService) {
                        isPlayIng = musicPlayerService.isPlaying(1);
                    }

                    JSONObject obj = new JSONObject();

                    Log.i(TAG, "222-isPlayIng  ==  " + isPlayIng);

                    if (isPlayIng) {
                        saveAsFileInfo(true);
                        view.setBackgroundResource(R.mipmap.read_float_window_play);
                        pauseMusic(1);
                        pauseMusic(2);

                        try {
                            obj.put(Constant.KEY_NAME_NOVEL_ID, currentBean.getNovelId());
                            obj.put(Constant.KEY_NAME_PLAY_TYPE, "2");
                        } catch (Exception e) {
                            LogUtil.e(TAG, "handleMessage--e  ==  " + e.getMessage());
                        }

                        //点击悬浮框上的暂停按钮，调用 js 方法，让
                        //H5 的听单页面上 正在播放的 item 从 暂停按钮 展示为 播放按钮
                        //参数是 当前播放的  文件id
                    } else {
                        try {
                            obj.put(Constant.KEY_NAME_NOVEL_ID, currentBean.getNovelId());
                            obj.put(Constant.KEY_NAME_PLAY_TYPE, "1");
                        } catch (Exception e) {
                            LogUtil.e(TAG, "handleMessage--e  ==  " + e.getMessage());
                        }

                        view.setBackgroundResource(R.mipmap.read_float_window_pause);
                        musicPlayerService.startPlayer();
                    }

                    if (null != currentBean) {
                        androidCallJavaScript(13, obj.toString());
                    }
                } else {
                    view.setEnabled(false);
                    RotationUtil.startRotation(view);
                    view.setBackgroundResource(R.mipmap.read_float_window_pause);
                    getFileInfo(userInfo.getUserId());
                }
            }
        });

        return floatView;
    }

    /**
     * 取消显示 可拖拽的悬浮框
     */
    private void cancelEasyWindow() {
        EasyWindow.recycleAllWindow();
    }

    /**
     * 内部类
     */
    protected class CustomClient extends WebViewClient {

        @Override
        public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
            if (Constant.TYPE_LOAD_FINISHED == view.getProgress()) {
                Log.i(TAG, "onPageFinished  ......" + url);
            }
        }

        @Override
        public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
            super.onReceivedError(view, request, error);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                Log.i(TAG, "onReceivedError  error......  ==  " + error.getErrorCode());
            }
            Log.i(TAG, "onReceivedError  request......  ==  " + request);
            /*String param = checkAuth();
            if (!TextUtils.isEmpty(param)) {
                view.loadUrl(MD5Util.URL + param);
                SharedPreferences sharedPreferences = getSharedPreferences("system", Context.MODE_PRIVATE); //私有数据
                SharedPreferences.Editor editor = sharedPreferences.edit();//获取编辑器
                editor.remove("httpUrl");
                editor.apply();//提交修改
            }*/
        }

        @SuppressLint("WebViewClientOnReceivedSslError")
        @Override
        public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
            LogUtil.e(TAG, "onReceivedSslError  ......");
            handler.proceed();
        }
    }

    private void playMusic(FloatWindowBean bean) {
        Log.i(TAG, "playMusic-bean  ==  " + bean);
        if (isServiceBound) {
            musicPlayerService.playAudio(bean, Constant.PLAYER_ID_1);
            if (!TextUtils.isEmpty(bean.getUrl2())) {
                if (!TextUtils.isEmpty(musicPlayerService.getUrl2())) {
                    if (!bean.getUrl2().equals(musicPlayerService.getUrl2())) {
                        musicPlayerService.stopAudio(2);
                        musicPlayerService.playAssetsMp3(bean.getUrl2());
                    }
                } else {
                    musicPlayerService.playAssetsMp3(bean.getUrl2());
                }
            }
        }
    }

    private void pauseMusic(int playerId) {
        if (isServiceBound) {
            musicPlayerService.pauseAudio(playerId);
        }
    }

    private void stopMusic(int playerId) {
        if (isServiceBound) {
            musicPlayerService.stopAudio(playerId);
        }
    }

    private void checkAndRequestPermissions(File file, int type) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
            handleLegacyPermissions(file, type);
        } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) {
            handleAndroid10Permissions(file, type);
        } else {
            handleAndroid11PlusPermissions(file, type);
        }
    }

    /**
     * Android 9及以下版本处理
     * @param file  查询的文件夹目录
     * @param type  type：1 获取文件目录；2 搜索文件
     */
    private void handleLegacyPermissions(File file, int type) {
        XXPermissions.with(ReadWebViewActivity.this)
                .permission(Permission.READ_EXTERNAL_STORAGE, Permission.WRITE_EXTERNAL_STORAGE)
                .request(new OnPermissionCallback() {
                    @Override
                    public void onGranted(@NonNull List<String> permissions, boolean allGranted) {
                        runOnUiThread(() -> {
                            if (type == 1) {
                                loadFiles(file);
                            } else {
                                loadDefaultFiles();
                            }
                        });
                    }

                    @Override
                    public void onDenied(@NonNull List<String> permissions, boolean doNotAskAgain) {
                        Toast.makeText(ReadWebViewActivity.this, "请授予存储权限以访问文件", Toast.LENGTH_SHORT).show();
                    }
                });
    }

    /**
     * Android 10特殊处理
     * @param file  查询的文件夹目录
     * @param type  type：1 获取文件目录；2 搜索文件
     */
    @RequiresApi(api = Build.VERSION_CODES.Q)
    private void handleAndroid10Permissions(File file, int type) {
        XXPermissions.with(ReadWebViewActivity.this)
                .permission(Permission.READ_EXTERNAL_STORAGE, Permission.MANAGE_EXTERNAL_STORAGE)
                .request(new OnPermissionCallback() {
                    @Override
                    public void onGranted(@NonNull List<String> permissions, boolean allGranted) {
                        runOnUiThread(() -> {
                            if (type == 1) {
                                loadFiles(file);
                            } else {
                                loadDefaultFiles();
                            }
                        });
                    }

                    @Override
                    public void onDenied(@NonNull List<String> permissions, boolean doNotAskAgain) {
                        Toast.makeText(ReadWebViewActivity.this, "请授予存储权限以访问文件", Toast.LENGTH_SHORT).show();
                    }
                });
    }

    /**
     * Android 11及以上版本处理
     * @param file  查询的文件夹目录
     * @param type  type：1 获取文件目录；2 搜索文件
     */
    @RequiresApi(api = Build.VERSION_CODES.R)
    private void handleAndroid11PlusPermissions(File file, int type) {
        if (Environment.isExternalStorageManager()) {
            if (type == 1) {
                loadFiles(file);
            } else {
                loadDefaultFiles();
            }
        } else {
            resultType = type;
            resultFile = file;

            Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
            intent.setData(Uri.parse("package:" + getPackageName()));
            startActivityForResult(intent, REQUEST_MANAGE_STORAGE);
        }
    }

    /**
     * 搜索全部 文件，包含 txt、pdf、doc
     */
    private void loadDefaultFiles() {
        fileList.clear();
        singleThreadPool.execute(() -> {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                searchMediaStoreFiles(Constant.FILE_DOC);
                searchMediaStoreFiles(Constant.FILE_PDF);
                searchMediaStoreFiles(Constant.FILE_TXT);
            } else {
                searchFilesLegacy(Constant.FILE_TXT);
                searchFilesLegacy(Constant.FILE_PDF);
                searchFilesLegacy(Constant.FILE_DOC);
            }
            sortAndUpdateUi(5);
        });
    }

    @RequiresApi(api = Build.VERSION_CODES.Q)
    private void searchMediaStoreFiles(String extension) {
        ContentResolver resolver = getContentResolver();
        Uri uri = MediaStore.Files.getContentUri("external");
        String[] projection = {
                MediaStore.Files.FileColumns.DATA,
                MediaStore.Files.FileColumns.DISPLAY_NAME,
                // 单位：Bytes（字节）
                MediaStore.Files.FileColumns.SIZE,
                MediaStore.Files.FileColumns.DATE_ADDED
        };
        String selection = MediaStore.Files.FileColumns.MIME_TYPE + "=? OR " +
                MediaStore.Files.FileColumns.MIME_TYPE + "=? OR " +
                MediaStore.Files.FileColumns.MIME_TYPE + "=?";

        String[] selectionArgs;
        if (Constant.FILE_TXT.equals(extension)) {
            selectionArgs = new String[]{"text/plain"};
        } else if (Constant.FILE_PDF.equals(extension)) {
            selectionArgs = new String[]{"application/pdf"};
        } else {
            selectionArgs = new String[]{"application/msword"};
        }

        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());

        try (Cursor cursor = resolver.query(uri, projection, selection, selectionArgs, null)) {
            if (cursor != null) {
                int pathIndex = cursor.getColumnIndex(MediaStore.Files.FileColumns.DATA);
                int nameIndex = cursor.getColumnIndex(MediaStore.Files.FileColumns.DISPLAY_NAME);
                int sizeIndex = cursor.getColumnIndex(MediaStore.Files.FileColumns.SIZE);
                int dateAddedIndex = cursor.getColumnIndex(MediaStore.Files.FileColumns.DATE_ADDED);

                while (cursor.moveToNext()) {
                    String path = cursor.getString(pathIndex);
                    String name = cursor.getString(nameIndex);
                    // 获取字节大小（long 类型）
                    long sizeBytes = cursor.getLong(sizeIndex);
                    long dateAddedSeconds = cursor.getLong(dateAddedIndex);

                    // 转换为 MB（1 MB = 1024 * 1024 Bytes）
                    double sizeMb = sizeBytes / (1024.0 * 1024.0);
                    // 保留2位小数
                    String formattedSize = String.format(Locale.getDefault(), "%.2fMB", sizeMb);

                    Date createTime = new Date(dateAddedSeconds * 1000L);
                    String formattedDate = dateFormat.format(createTime);

                    File file = new File(path);
                    if (file.exists() && file.isFile()) {
                        CustomFile customFile = new CustomFile(name, path, formattedDate, formattedSize, 0);
                        fileList.add(customFile);
                    }
                }
            }
        } catch (Exception e) {
            LogUtil.e(TAG, "MediaStore查询错误", e);
        }
    }

    private void searchFilesLegacy(String extension) {
        File root = Environment.getExternalStorageDirectory();
        searchFilesRecursive(root, extension);
    }

    private void searchFilesRecursive(File directory, String extension) {
        if (directory == null || !directory.isDirectory()) {
            return;
        }

        File[] files = directory.listFiles();
        if (files == null) {
            return;
        }

        for (File file : files) {
            if (file.isDirectory()) {
                searchFilesRecursive(file, extension);
            } else if (file.getName().toLowerCase().endsWith(extension.toLowerCase())) {
                CustomFile customFile = new CustomFile(file.getName(),
                        file.getAbsolutePath(),
                        getFileSizeInMb(file.getAbsolutePath()),
                        getFileLastModifiedTime(file.getAbsolutePath()), 0);
                fileList.add(customFile);
            }
        }
    }

    /**
     * 获取文件大小（MB）
     *
     * @param filePath 文件路径
     * @return 文件大小（MB），如 "5.25MB"
     */
    public static String getFileSizeInMb(String filePath) {
        File file = new File(filePath);
        if (file.exists()) {
            long sizeBytes = file.length();
            double sizeMb = sizeBytes / (1024.0 * 1024.0);
            return String.format(Locale.getDefault(), "%.2fMB", sizeMb);
        }
        // 文件不存在时返回 0MB
        return "0MB";
    }

    /**
     * 获取文件的最后修改时间（年-月-日）
     *
     * @param filePath 文件路径
     * @return 格式化后的时间，如 "2023-05-20"
     */
    public static String getFileLastModifiedTime(String filePath) {
        File file = new File(filePath);
        if (file.exists()) {
            // 毫秒级时间戳
            long lastModifiedTime = file.lastModified();
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
            return dateFormat.format(new Date(lastModifiedTime));
        }
        // 文件不存在时返回 "N/A"
        return "N/A";
    }

    private void sortAndUpdateUi(int type) {
        Collections.sort(fileList, (f1, f2) -> {
            String ext1 = getFileExtension(f1);
            String ext2 = getFileExtension(f2);

            int priority1 = getExtensionPriority(ext1);
            int priority2 = getExtensionPriority(ext2);

            if (priority1 != priority2) {
                return Integer.compare(priority1, priority2);
            }
            return f1.getFileName().compareToIgnoreCase(f2.getFileName());
        });

        Collections.sort(fileList, new Comparator<CustomFile>() {
            @Override
            public int compare(CustomFile f1, CustomFile f2) {
                // 按 createTi 降序（最近到最早）
                return f2.getCreateTi().compareTo(f1.getCreateTi());
            }
        });

        runOnUiThread(() -> {
            Gson gson = new Gson();
            String json = gson.toJson(fileList);
            androidCallJavaScript(type, json);
        });
    }

    private String getFileExtension(CustomFile file) {
        String name = file.getFileName();
        int lastDot = name.lastIndexOf('.');
        return lastDot == -1 ? "" : name.substring(lastDot).toLowerCase();
    }

    private int getExtensionPriority(String ext) {
        switch (ext.toLowerCase()) {
            case ".txt":
                return 1;
            case ".pdf":
                return 2;
            case ".doc":
                return 3;
            case ".docx":
                return 4;
            default:
                return 5;
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == REQUEST_PERMISSION_CODE && grantResults.length > 0) {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                loadDefaultFiles();
            } else {
                showAlternativeFilePicker();
            }
        }
    }

    private void handleSelectedFile(Uri uri) {
        try (Cursor cursor = getContentResolver().query(
                uri,
                new String[]{OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE},
                null, null, null)) {

            if (cursor != null && cursor.moveToFirst()) {
                String name = cursor.getString(0);
                long size = cursor.getLong(1);
                String message = String.format(
                        "文件名: %s\n路径: %s\n大小: %s",
                        name, uri.toString(), formatFileSize(size)
                );
                Toast.makeText(this, message, Toast.LENGTH_LONG).show();
            }
        } catch (Exception e) {
            LogUtil.e(TAG, "处理选中文件错误", e);
        }
    }

    @SuppressLint("DefaultLocale")
    private String formatFileSize(long size) {
        if (size <= 0) {
            return "0 B";
        }
        String[] units = {"B", "KB", "MB", "GB", "TB"};
        int digitGroups = (int) (Math.log10(size) / Math.log10(1024));
        return String.format("%.1f %s", size / Math.pow(1024, digitGroups), units[digitGroups]);
    }

    private void showAlternativeFilePicker() {

        Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("*/*");
        intent.putExtra(Intent.EXTRA_MIME_TYPES, new String[]{
                "text/plain",
                "application/pdf",
                "application/msword",
                "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
        });
        startActivityForResult(intent, REQUEST_FILE_PICKER);
    }

    private boolean isExtensionSearch(String query) {
        return Constant.FILE_TXT.equals(query) || Constant.FILE_PDF.equals(query)
                || Constant.FILE_DOC.equals(query);
    }

    private void handleExtensionSearch(String query) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            if (Constant.FILE_TXT.equals(query)) {
                searchMediaStoreFiles(Constant.FILE_TXT);
            } else if (Constant.FILE_PDF.equals(query)) {
                searchMediaStoreFiles(Constant.FILE_PDF);
            } else if (Constant.FILE_DOC.equals(query)) {
                searchMediaStoreFiles(Constant.FILE_DOC);
            } else {
                searchMediaStoreFiles(Constant.FILE_TXT);
                searchMediaStoreFiles(Constant.FILE_PDF);
                searchMediaStoreFiles(Constant.FILE_DOC);
            }
        } else {
            if (Constant.FILE_TXT.equals(query)) {
                searchFilesLegacy(Constant.FILE_TXT);
            } else if (Constant.FILE_PDF.equals(query)) {
                searchFilesLegacy(Constant.FILE_PDF);
            } else if (Constant.FILE_DOC.equals(query)) {
                searchFilesLegacy(Constant.FILE_DOC);
            } else {
                searchFilesLegacy(Constant.FILE_TXT);
                searchFilesLegacy(Constant.FILE_PDF);
                searchFilesLegacy(Constant.FILE_DOC);
            }
        }
    }

    private void handleExactSearch(String query) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            searchExactFileMediaStore(query);
        } else {
            searchExactFileLegacy(query);
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.Q)
    private void searchExactFileMediaStore(String exactName) {
        ContentResolver resolver = getContentResolver();
        Uri uri = MediaStore.Files.getContentUri("external");

        String[] projection = {
                MediaStore.Files.FileColumns.DATA,
                MediaStore.Files.FileColumns.DISPLAY_NAME,
                // 单位：Bytes（字节）
                MediaStore.Files.FileColumns.SIZE,
                MediaStore.Files.FileColumns.DATE_ADDED
        };

        String selection = "(" + MediaStore.Files.FileColumns.DISPLAY_NAME + " LIKE ?) AND ("
                + MediaStore.Files.FileColumns.MIME_TYPE + " IN (?, ?, ?))";

        String[] selectionArgs = new String[]{
                "%" + exactName + "%",
                // txt 文件的 MIME 类型
                "text/plain",
                // pdf 文件的 MIME 类型
                "application/pdf",
                // doc 文件的 MIME 类型
                "application/msword"
        };

        try (Cursor cursor = resolver.query(uri, projection, selection, selectionArgs, null)) {

            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());

            if (cursor != null) {

                int pathIndex = cursor.getColumnIndex(MediaStore.Files.FileColumns.DATA);
                int nameIndex = cursor.getColumnIndex(MediaStore.Files.FileColumns.DISPLAY_NAME);
                int sizeIndex = cursor.getColumnIndex(MediaStore.Files.FileColumns.SIZE);
                int dateAddedIndex = cursor.getColumnIndex(MediaStore.Files.FileColumns.DATE_ADDED);

                while (cursor.moveToNext()) {
                    String path = cursor.getString(pathIndex);
                    String name = cursor.getString(nameIndex);
                    // 获取字节大小（long 类型）
                    long sizeBytes = cursor.getLong(sizeIndex);
                    long dateAddedSeconds = cursor.getLong(dateAddedIndex);

                    // 转换为 MB（1 MB = 1024 * 1024 Bytes）
                    double sizeMb = sizeBytes / (1024.0 * 1024.0);
                    // 保留2位小数
                    String formattedSize = String.format(Locale.getDefault(), "%.2fMB", sizeMb);

                    Date createTime = new Date(dateAddedSeconds * 1000L);
                    String formattedDate = dateFormat.format(createTime);

                    File file = new File(path);
                    if (file.exists() && file.isFile()) {
                        CustomFile customFile = new CustomFile(name, path, formattedDate, formattedSize, 0);
                        fileList.add(customFile);
                    }
                }
            }
        } catch (Exception e) {
            LogUtil.e(TAG, "精确搜索错误", e);
        }
    }

    private void searchExactFileLegacy(String exactName) {
        File root = Environment.getExternalStorageDirectory();
        searchExactFileRecursive(root, exactName);
    }

    private void searchExactFileRecursive(File directory, String exactName) {
        if (directory == null || !directory.isDirectory()) {
            return;
        }

        File[] files = directory.listFiles();
        if (files == null) {
            return;
        }

        for (File file : files) {
            if (file.isDirectory()) {
                searchExactFileRecursive(file, exactName);
            } else if (file.getName().equalsIgnoreCase(exactName)) {
                CustomFile customFile = new CustomFile(file.getName(),
                        file.getAbsolutePath(),
                        getFileSizeInMb(file.getAbsolutePath()),
                        getFileLastModifiedTime(file.getAbsolutePath()), 0);
                fileList.add(customFile);
            }
        }
    }

    private void loadFiles(File directory) {

        singleThreadPool.execute(new Runnable() {
            @Override
            public void run() {

                fileList.clear();
                File[] files = directory.listFiles();

                if (files != null && files.length > 0) {
                    List<File> dirs = new ArrayList<>();
                    List<File> fileItems = new ArrayList<>();

                    for (File file : files) {
                        if (file.isDirectory()) {
                            dirs.add(file);
                        } else {
                            if (file.getName().endsWith(Constant.FILE_DOC)
                                    || file.getName().endsWith(Constant.FILE_PDF)
                                    || file.getName().endsWith(Constant.FILE_TXT)) {
                                fileItems.add(file);
                            }
                        }
                    }

                    // Sort directories and files alphabetically
                    Collections.sort(dirs, (f1, f2) -> f1.getName().compareToIgnoreCase(f2.getName()));
                    Collections.sort(fileItems, (f1, f2) -> f1.getName().compareToIgnoreCase(f2.getName()));

                    for (int i = 0; i < dirs.size(); i++) {
                        CustomFile dir = new CustomFile(dirs.get(i).getName(),
                                dirs.get(i).getAbsolutePath(), "", "", 1);
                        fileList.add(dir);
                    }

                    for (int i = 0; i < fileItems.size(); i++) {
                        CustomFile file = new CustomFile(fileItems.get(i).getName(),
                                fileItems.get(i).getAbsolutePath(),
                                getFileLastModifiedTime(fileItems.get(i).getAbsolutePath()),
                                getFileSizeInMb(fileItems.get(i).getAbsolutePath()), 0);
                        fileList.add(file);
                    }
                }

                runOnUiThread(() -> {
                    Gson gson = new Gson();
                    String json = gson.toJson(fileList);
                    androidCallJavaScript(7, json);
                });
            }
        });
    }

    private void saveAsFileInfo(boolean from) {

        Log.i(TAG, "saveAsFileInfo--currentBean  ==  " + currentBean);
        if (null != currentBean) {
            SaveFileInfoBean bean = new SaveFileInfoBean();
            bean.setUserId(userInfo.getUserId());
            bean.setFileId(currentBean.getNovelId());
            bean.setChapterId(currentBean.getChapterId());
            bean.setSliceId(currentBean.getSliceId());
            bean.setFont(currentBean.getFont());
            bean.setAnchor(currentBean.getAnchorName());
            bean.setCloseTime(currentBean.getCloseTime());
            bean.setSpeed(currentBean.getSpeed());
            bean.setCirculationMode(currentBean.getCirculationMode());
            bean.setCurrentIndex(currentBean.getCurrentIndex());
            bean.setReadType(currentBean.getReadType());
            bean.setCharIndex(currentBean.getCharIndex());
            bean.setProgressValue(currentBean.getProgressValue());
            bean.setTextIndex(currentBean.getTextIndex());
            bean.setVolume(currentBean.getVolume());
            if (null != musicPlayerService) {
                int position = musicPlayerService.getCurrentPosition(1);
                int total = musicPlayerService.getTotalDuration(1);

                Log.i(TAG, "saveAsFileInfo--position  ==  " + position);
                Log.i(TAG, "total  ==  " + total);
                Log.i(TAG, "progressValue  ==  " + percentageCalculation(position, total));
                Log.i(TAG, "currentBean.getIndex()  ==  " + currentBean.getIndex());
                Log.i(TAG, "charIndex  ==  " + (currentBean.getContentLength() * percentageCalculation(position, total) / 100));
                bean.setSeekPosition(position + "");
                bean.setProgressValue(String.valueOf((int) Math.floor(percentageCalculation(position, total))));
                bean.setTextIndex(String.valueOf(currentBean.getIndex()));
                bean.setCharIndex(String.valueOf((int) Math.floor(currentBean.getContentLength() * percentageCalculation(position, total) / 100)));
            }
            saveFileInfo(bean, from);
        }
    }

    /**
     * 计算百分比
     * @param position  音频当前播放位置
     * @param total     音频一共能播放多少秒
     * @return          百分比
     */
    public double percentageCalculation(double position, double total) {
        return (position / total) * 100;
    }

    /******************************网络接口开始*******************************/
    /**
     * 单个文件上传
     * @param url   接口
     * @param file  上传的文件
     * @param fileParamName 文件参数名称
     * @param fileName  文件名称
     */
    private void uploadFile(String url, File file, String fileParamName, String fileName) {

        OkHttpClient client = DownloaderUtil.getUnsafeOkHttpClient();
        // 1. 创建MultipartBody
        RequestBody requestBody = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart(fileParamName, fileName,
                        RequestBody.create(file, MediaType.parse("application/octet-stream")))
                // 可以添加其他参数
                // .addFormDataPart("key", "value")
                .build();

        // 2. 创建请求
        Request request = new Request.Builder()
                .url(url)
                .post(requestBody)
                .build();

        // 3. 异步执行请求
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(@NonNull Call call, @NonNull IOException e) {
                e.printStackTrace();
                // 处理失败情况
            }

            @Override
            public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                if (!response.isSuccessful()) {
                    throw new IOException("Unexpected code " + response);
                }
                // 处理响应
                if (null != response.body()) {
                    String responseData = response.body().string();
                    System.out.println("responseData  ==  " + responseData);
                }
            }
        });
    }

    public void uploadFiles(List<File> files,
                            String anchorName,
                            String speed,
                            String volume) {
        try {
            // 使用工具类创建Builder
            MultipartBody.Builder builder = multipartHelper.createBaseBuilder();

            // 添加可选参数
            multipartHelper.addOptionalParam(builder, "anchorName", anchorName, "default");
            multipartHelper.addOptionalParam(builder, "speed", speed, "1.0");
            multipartHelper.addOptionalParam(builder, "volume", volume, "1.0");

            // 添加文件
            multipartHelper.addFiles(builder, files);

            // 创建请求
            Request request = multipartHelper.createRequestBuilder(
                    Constant.API_NAME_UPLOADS,
                    builder
            ).build();

            // 发送请求并处理响应
            DownloaderUtil.getUnsafeOkHttpClient().newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(@NonNull Call call, @NonNull IOException e) {
                    e.printStackTrace();
                }

                @Override
                public void onResponse(@NonNull Call call, @NonNull Response response) {
                    try (ResponseBody responseBody = response.body()) {
                        if (!response.isSuccessful()) {
                            LogUtil.e(TAG, "Unexpected code " + response);
                            androidCallJavaScript(8, "文件上传失败");
                            return;
                        }

                        if (null == responseBody) {
                            LogUtil.e(TAG, "responseBody is null");
                            androidCallJavaScript(8, "文件上传失败");
                            return;
                        }

                        String responseData = responseBody.string();

                        // 尝试解析为JSON
                        try {
                            JSONObject json = new JSONObject(responseData);
                            JSONArray arrays = json.getJSONArray("data");
                            boolean result;
                            if (arrays.length() != 0) {
                                Log.i(TAG, "arrays:  ==  " + arrays);
                                result = true;
                            } else {
                                result = false;
                            }

                            runOnUiThread(() -> {
                                if (result) {
                                    androidCallJavaScript(8, "文件上传成功");
                                } else {
                                    androidCallJavaScript(8, "文件上传失败");
                                }
                                Log.i(TAG, "上传文件的结果是  ==  " + result);
                            });
                        } catch (JSONException e) {
                            LogUtil.e(TAG, "Malformed JSON", e);
                            androidCallJavaScript(8, "文件上传失败");
                        }
                    } catch (Exception e) {
                        androidCallJavaScript(8, "文件上传失败");
                        LogUtil.e(TAG, "Error reading response", e);
                    }
                }
            });

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void getNextFileSlice(FloatWindowBean bean, NextAudioCallback callback) {
        Log.i(TAG, "getNextFileSlice currentBean: " + bean);
        try {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("fileId", bean.getNovelId());
            jsonObject.put("chapterId", bean.getChapterId());
            jsonObject.put("sliceId", bean.getSliceId());
            jsonObject.put("sliceIndex", bean.getCurrentIndex() + 1);
            jsonObject.put("type", bean.getReadType());
            jsonObject.put("speed", bean.getSpeed());
            jsonObject.put("volume", bean.getVolume());
            jsonObject.put("anchorName", bean.getAnchorName());

            Request request = multipartHelper.createJsonRequestBuilder(
                    Constant.API_NAME_FILE_SLICE,
                    jsonObject.toString()
            ).build();

            DownloaderUtil.getUnsafeOkHttpClient().newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(@NonNull Call call, @NonNull IOException e) {
                    LogUtil.e(TAG, "onFailure  ==  ");
                    callback.onError(e);
                }

                @Override
                public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                    if (response.isSuccessful() && response.body() != null) {
                        String responseBody = response.body().string();
                        Gson gson = new Gson();
                        Type responseType = new TypeToken<BaseResponse<FileSliceInfo>>() {
                        }.getType();
                        BaseResponse<FileSliceInfo> baseResponse = gson.fromJson(responseBody, responseType);

                        if (baseResponse.getCode() == 0 && baseResponse.getData() != null) {
                            FileSliceInfo sliceInfo = baseResponse.getData();
                            Log.i(TAG, "sliceInfo222  ==  " + sliceInfo);
                            bean.setCurrentIndex(sliceInfo.getSliceIndex());
                            bean.setSliceId(sliceInfo.getSliceFileId());
                            bean.setChapterId(sliceInfo.getChapterId());
                            bean.setIndex(sliceInfo.getIndex());
                            bean.setTotal(sliceInfo.getTotal());
                            bean.setContentLength(sliceInfo.getSliceContent().length());
                            getPlayUrl(bean, sliceInfo.getSliceFileId(), callback);
                        } else {
                            callback.onError(new Exception("Invalid response data"));
                        }
                    } else {
                        callback.onError(new Exception("Request failed"));
                    }
                }
            });
        } catch (Exception e) {
            callback.onError(e);
        }
    }

    private void getPlayUrl(FloatWindowBean bean, String fileId, NextAudioCallback callback) {

        Log.i(TAG, "getPlayUrl--bean  ==  " + bean);
        MultipartBody.Builder builder = multipartHelper.createBaseBuilder();
        builder.addFormDataPart("fileId", fileId);

        Request request = multipartHelper.createRequestBuilder(
                Constant.API_NAME_FILE_PREVIEW,
                builder
        ).build();

        DownloaderUtil.getUnsafeOkHttpClient().newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(@NonNull Call call, @NonNull IOException e) {
                callback.onError(e);
            }

            @Override
            public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                if (response.isSuccessful() && response.body() != null) {
                    String responseBody = response.body().string();
                    Gson gson = new Gson();
                    Type responseType = new TypeToken<BaseResponse<String>>() {
                    }.getType();
                    BaseResponse<String> baseResponse = gson.fromJson(responseBody, responseType);

                    if (baseResponse.getCode() == 0 && baseResponse.getData() != null) {
                        bean.setUrl1(baseResponse.getData());
                        bean.setSeekPosition(0 + "");
                        currentBean = bean;
                        callback.onNextAudioReady(bean);
                    } else {
                        callback.onError(new Exception("Invalid URL response"));
                    }
                } else {
                    callback.onError(new Exception("URL request failed"));
                }
            }
        });
    }

    /**
     * 保存配置
     * @param bean  配置信息bean
     * @param from  点击的是悬浮框上的暂停按钮，还是关闭按钮。
     *              只有点击悬浮框上的暂停按钮 from 是 true，其它都是false
     */
    private void saveFileInfo(SaveFileInfoBean bean, boolean from) {
        Log.i(TAG, "saveFileInfo  ==  " + bean);
        try {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("userId", bean.getUserId());
            jsonObject.put("fileId", bean.getFileId());
            jsonObject.put("chapterId", bean.getChapterId());
            jsonObject.put("sliceId", bean.getSliceId());
            jsonObject.put("music", bean.getMusic());
            jsonObject.put("font", bean.getFont());
            jsonObject.put("anchor", bean.getAnchor());
            jsonObject.put("closeTime", bean.getCloseTime());
            jsonObject.put("speed", bean.getSpeed());
            jsonObject.put("circulationMode", bean.getCirculationMode());
            jsonObject.put("currentIndex", bean.getCurrentIndex());
            jsonObject.put("seekPosition", bean.getSeekPosition());
            jsonObject.put("textIndex", bean.getTextIndex());
            jsonObject.put("progressValue", bean.getProgressValue());
            jsonObject.put("charIndex", bean.getCharIndex());

            Request request = multipartHelper.createJsonRequestBuilder(
                    Constant.API_NAME_FILE_SAVE,
                    jsonObject.toString()
            ).build();

            DownloaderUtil.getUnsafeOkHttpClient().newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(@NonNull Call call, @NonNull IOException e) {

                }

                @Override
                public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                    if (response.isSuccessful() && response.body() != null) {
                        String responseBody = response.body().string();
                        Gson gson = new Gson();
                        Type responseType = new TypeToken<BaseResponse<Boolean>>() {
                        }.getType();
                        BaseResponse<Boolean> baseResponse = gson.fromJson(responseBody, responseType);
                        if (baseResponse.getCode() == 0 && null != baseResponse.getData() && baseResponse.getData()) {
                            if (!from) {
                                currentBean = null;
                            }
                        }
                    }
                }
            });
        } catch (Exception e) {
            LogUtil.e(TAG, "saveFileInfo error: " + e.getMessage());
        }
    }

    /**
     * 获取用户最后一次播放的文件和配置
     * @param userId    用户id
     */
    private void getFileInfo(String userId) {
        try {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("userId", userId);

            Request request = multipartHelper.createJsonRequestBuilder(
                    Constant.API_NAME_FILE_AUDIO,
                    jsonObject.toString()
            ).build();

            DownloaderUtil.getUnsafeOkHttpClient().newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(@NonNull Call call, @NonNull IOException e) {
                    LogUtil.e(TAG, "getFileInfo failed: " + e.getMessage());
                    showNoPlaylistMessage();
                }

                @Override
                public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                    if (response.isSuccessful() && response.body() != null) {
                        String responseBody = response.body().string();
                        Gson gson = new Gson();
                        Type responseType = new TypeToken<BaseResponse<AudioRecordInfo>>() {
                        }.getType();
                        BaseResponse<AudioRecordInfo> baseResponse = gson.fromJson(responseBody, responseType);
                        if (null != baseResponse && baseResponse.getCode() == 0 && null != baseResponse.getData()) {
                            AudioRecordInfo audioRecordInfo = baseResponse.getData();
                            Log.i(TAG, "audioRecordInfo  ==  " + audioRecordInfo);
                            if (null != audioRecordInfo) {
                                FloatWindowBean bean = new FloatWindowBean();
                                bean.setCurrentIndex(audioRecordInfo.getCurrentIndex());
                                bean.setReadType(audioRecordInfo.getReadType());
                                bean.setNovelId(audioRecordInfo.getFileId());
                                bean.setChapterId(audioRecordInfo.getChapterId());
                                bean.setFont(audioRecordInfo.getFont());
                                bean.setAnchorName(audioRecordInfo.getAnchor());
                                bean.setSpeed(audioRecordInfo.getSpeed());
                                bean.setCirculationMode(audioRecordInfo.getCirculationMode());
                                bean.setSeekPosition(audioRecordInfo.getSeekPosition());
                                getCurrentFileSlice(bean);
                            }
                        } else {
                            showNoPlaylistMessage();
                        }
                    }
                }
            });
        } catch (Exception e) {
            showNoPlaylistMessage();
        }
    }

    private void showNoPlaylistMessage() {
        runOnUiThread(() -> {
            if (btnImg != null) {
                btnImg.setEnabled(true);
                RotationUtil.stopRotation(btnImg);
                btnImg.setBackgroundResource(R.mipmap.read_float_window_play);
                Toaster.show("暂无听单");
            }
        });
    }

    private void getCurrentFileSlice(FloatWindowBean bean) {
        Log.i(TAG, "getCurrentFileSlice bean: " + bean);
        try {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("fileId", bean.getNovelId());
            jsonObject.put("chapterId", bean.getChapterId());
            jsonObject.put("sliceId", bean.getSliceId());
            jsonObject.put("sliceIndex", bean.getCurrentIndex());
            jsonObject.put("type", bean.getReadType());
            jsonObject.put("speed", bean.getSpeed());
            jsonObject.put("volume", bean.getVolume());
            jsonObject.put("anchorName", bean.getAnchorName());

            Request request = multipartHelper.createJsonRequestBuilder(
                    Constant.API_NAME_FILE_SLICE,
                    jsonObject.toString()
            ).build();

            DownloaderUtil.getUnsafeOkHttpClient().newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(@NonNull Call call, @NonNull IOException e) {
                    LogUtil.e(TAG, "getCurrentFileSlice + e.getMessage()  ==  " + e.getMessage());
                }

                @Override
                public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                    if (response.isSuccessful() && response.body() != null) {
                        String responseBody = response.body().string();
                        Gson gson = new Gson();
                        Type responseType = new TypeToken<BaseResponse<FileSliceInfo>>() {
                        }.getType();
                        BaseResponse<FileSliceInfo> baseResponse = gson.fromJson(responseBody, responseType);

                        if (baseResponse.getCode() == 0 && baseResponse.getData() != null) {
                            FileSliceInfo sliceInfo = baseResponse.getData();
                            Log.i(TAG, "sliceInfo111  ==  " + sliceInfo);
                            bean.setCurrentIndex(sliceInfo.getSliceIndex());
                            bean.setSliceId(sliceInfo.getSliceFileId());
                            bean.setChapterId(sliceInfo.getChapterId());
                            bean.setIndex(sliceInfo.getIndex());
                            bean.setTotal(sliceInfo.getTotal());
                            bean.setSliceContent(sliceInfo.getSliceContent());
                            bean.setContentLength(sliceInfo.getSliceContent().length());
                            getCurrentPlayUrl(bean, sliceInfo.getSliceFileId());
                        }
                    }
                }
            });
        } catch (Exception e ) {
            LogUtil.e(TAG, "getCurrentFileSlice error: " + e.getMessage());
        }
    }

    private void getCurrentPlayUrl(FloatWindowBean bean, String fileId) {
        try {
            MultipartBody.Builder builder = multipartHelper.createBaseBuilder();
            builder.addFormDataPart("fileId", fileId);

            Request request = multipartHelper.createRequestBuilder(
                    Constant.API_NAME_FILE_PREVIEW,
                    builder
            ).build();

            DownloaderUtil.getUnsafeOkHttpClient().newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(@NonNull Call call, @NonNull IOException e) {
                    LogUtil.e(TAG, "getCurrentPlayUrl + e.getMessage()  ==  " + e.getMessage());
                }

                @Override
                public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                    if (response.isSuccessful() && response.body() != null) {
                        String responseBody = response.body().string();
                        Gson gson = new Gson();
                        Type responseType = new TypeToken<BaseResponse<String>>() {}.getType();
                        BaseResponse<String> baseResponse = gson.fromJson(responseBody, responseType);

                        if (baseResponse.getCode() == 0 && baseResponse.getData() != null) {
                            bean.setUrl1(baseResponse.getData());
                            currentBean = bean;
                            Log.i(TAG, "getCurrentPlayUrl - currentBean  ==  " + currentBean);
                            String fileName = bean.getChapterId() + "_" + System.currentTimeMillis() + ".wav";
                            // 开始下载
                            DownloaderUtil.downloadWavFile(ReadWebViewActivity.this, currentBean, currentBean.getUrl1(), fileName, ReadWebViewActivity.this);
                        }
                    }
                }
            });
        } catch (Exception e) {
            LogUtil.e(TAG, "getCurrentPlayUrl error: " + e.getMessage());
        }
    }

    /******************************网络接口结束*******************************/

    @Override
    protected void onDestroy() {
        Log.i(TAG, "onDestroy  ......");

        //saveAsFileInfo(false);

        // 停止所有音乐播放
        if (isServiceBound && musicPlayerService != null) {
            musicPlayerService.stopAudio(1);
            musicPlayerService.stopAudio(2);
            musicPlayerService = null;
        }

        // 解绑服务
        if (isServiceBound) {
            unbindService(serviceConnection);
            isServiceBound = false;
        }

        // 停止服务（可选）
        stopService(new Intent(this, MusicPlayerService.class));

        // 释放 Messenger
        activityMessenger = null;

        super.onDestroy();
    }

    @Override
    public void onDownloadSuccess(FloatWindowBean bean, File file) {
        Log.i(TAG, "onDownloadSuccess  ==  " + currentType);
        if (file.exists()) {

            if (Constant.TYPE_CURRENT_PLAY != currentType) {
                bean.setFilePath(file.getAbsolutePath());
/*
                webView.evaluateJavascript("javascript:getBgMusic('')", new ValueCallback<String>() {
                    @Override
                    public void onReceiveValue(String value) {
                        Log.i(TAG, "getBgMusic-111-value  ==  " + value);
                        if (TextUtils.isEmpty(bean.getUrl2())) {
                            Log.i(TAG, "getBgMusic-222-value  ==  " + value);
                            Log.i(TAG, "");
                            if (!TextUtils.isEmpty(value) && value.length() > Constant.MIN_LENGTH) {
                                Log.i(TAG, "getBgMusic-333-value  ==  " + value);
                                bean.setUrl2(value.replace("\"", ""));
                            }
                        }

                        playMusic(bean);
                    }
                });
*/

                playMusic(bean);

                try {
                    JSONObject obj = new JSONObject();
                    obj.put(Constant.KEY_NAME_NOVEL_ID, bean.getNovelId());
                    obj.put(Constant.KEY_NAME_PLAY_TYPE, "1");
                    androidCallJavaScript(13, obj.toString());
                } catch (Exception e) {
                    LogUtil.e(TAG, "getFileInfo--e  ==  " + e.getMessage());
                }

                Gson gson = new Gson();
                String json = gson.toJson(true);
                androidCallJavaScript(9, json);

                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        isPlayIng = musicPlayerService.isPlaying(1);
                        btnImg.setEnabled(true);
                        RotationUtil.stopRotation(btnImg);
                        btnImg.setBackgroundResource(R.mipmap.read_float_window_pause);
                    }
                });
            } else {
                currentBean = null;
            }

            currentType = -1;
        }
    }

    @Override
    public void onDownloadFailed(Exception e) {}

    @Override
    public void onProgressUpdate(int progress) {
        Log.i(TAG, "progress  ==  " + progress);
    }

    @Override
    public void onDownloadCancelled() {
        runOnUiThread(() -> {
            // 更新UI，显示下载已取消
            Toast.makeText(this, "下载已取消", Toast.LENGTH_SHORT).show();
        });
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == REQUEST_MANAGE_STORAGE && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            if (Environment.isExternalStorageManager()) {
                if (resultType == 1) {
                    if (null != resultFile && resultFile.exists() && resultFile.isDirectory()) {
                        loadFiles(resultFile);
                    } else {
                        loadFiles(Environment.getExternalStorageDirectory());
                    }
                } else {
                    loadDefaultFiles();
                }
            }
        } else if (requestCode == REQUEST_FILE_PICKER && resultCode == RESULT_OK && data != null) {
            System.out.println("data.getData()  ==  " + data.getData());
            handleSelectedFile(data.getData());
        }
    }
}